package com.zhoug.demo.player.http;


import com.zhoug.common.http.core.ContentType;
import com.zhoug.common.utils.encrypt.IEncryptor;
import com.zhoug.logging.Logger;

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;

/**
 * 加解密密拦截器
 *
 * @Author 35574
 * @Date 2021/3/16
 * @Description
 */
public class EncryptInterceptor implements Interceptor {
    private static final String TAG = ">>>EncryptInterceptor";
    private static final boolean debug = true;
    private static final String SERIAL_NUMBER = "SerialNumber";
    private boolean encryptRequest;//是否加密Request
    private boolean encryptResponse;//是否解密response

    /**
     * 是否启用数据加密
     * true:启用,{@link #encryptRequest,#encryptResponse}配置才生效
     * false:禁用,{@link #encryptRequest,#encryptResponse}配置无效
     */
    private static  boolean encryptEnable=true;

    public static boolean getDefaultEncryptEnable() {
        return true;
    }

    public EncryptInterceptor(boolean encryptRequest, boolean encryptResponse) {
        this.encryptRequest = encryptRequest;
        this.encryptResponse = encryptResponse;
    }


    /**
     * 忽律加解密url
     * @param requestUrl
     * @return
     */
    private boolean ignore(String requestUrl){
        return !requestUrl.contains(DataManager.getBaseUrl());
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        if (encryptEnable) {
            Request request = chain.request();
            String stringUrl = request.url().toString();
            if (ignore(stringUrl)) {
                if (debug) {
                    Logger.d(TAG, "不加密:" + stringUrl);
                }
                return chain.proceed(chain.request());
            }
            //加密
            if (encryptRequest) {
                request = encryptRequest(request);
            }
            Response response = chain.proceed(request);
            if (encryptResponse) {
                //解密
                response = decryptResponse(response);
            }
            return response;
        }
        return chain.proceed(chain.request());
    }

    /**
     * 加密请求
     *
     * @param request
     * @return
     */
    private Request encryptRequest(Request request) throws IOException {
        if (debug) {
            Logger.d(TAG, "############加密request############");
        }
        //url参数
        String method = request.method();
        String requestUrl = request.url().url().toString();
        if (debug) {
            Logger.d(TAG, method + ":" + requestUrl);
        }
        //只加密post中的body中的数据
        if ("POST".equalsIgnoreCase(method)) {
            RequestBody body = request.body();
            if (body != null && body.contentLength() > 0) {
                if (body instanceof MultipartBody) {
                    //表单
                } else {
                    if (debug) {
                        Logger.d(TAG, "数据加密");
                    }
                    //非表单
                    Buffer buffer = new Buffer();
                    body.writeTo(buffer);
                    String s = buffer.readUtf8();
                    String aesKey = MyEncryptorHelper.generatorAesKey();
                    if (debug) {
                        Logger.d(TAG, "aesKey:" + aesKey);
                    }
                    IEncryptor aesHelper = MyEncryptorHelper.createAESHelper(aesKey);
                    String encrypt = aesHelper.encryptToBase64(s);
                    if (debug) {
                        Logger.d(TAG, "加密前:" + s);
//                        Logger.d(TAG, "加密后:" + encrypt);
                    }
//                    RequestBody requestBody = RequestBody.create(body.contentType(), encrypt);
                    RequestBody requestBody = RequestBody.create(MediaType.parse(ContentType.TEXT_PLAIN), encrypt);
                    Request.Builder newBuilder = request.newBuilder();
                    newBuilder.method(request.method(), requestBody)
                            //添加公匙到header
                            .removeHeader(SERIAL_NUMBER)//防止添加多个同名
                            .addHeader(SERIAL_NUMBER, MyEncryptorHelper.encryptKey(aesKey));//把加密后的AES密匙放入header
                    return newBuilder.build();
                }
            }
        }
        return request;
    }

    /**
     * 解密服务器返回的数据
     *
     * @param response
     * @return
     * @throws IOException
     */
    private Response decryptResponse(Response response) throws IOException {
        if (debug) {
            Logger.d(TAG, "############解密response############");
        }
        if (response.isSuccessful()) {
            ResponseBody body = response.body();
            if (body != null) {
                MediaType contentType = body.contentType();
                if (contentType != null) {
                    String mediaType = contentType.toString();
                    if (debug) {
                        Logger.d(TAG, "mediaType:" + mediaType);
                    }
                    if (shouldDecrypt(mediaType)) {
                        if (debug) {
                            Logger.d(TAG, "数据解密");
                        }
                        byte[] bytes = body.bytes();
                        String serialNumber = response.header(SERIAL_NUMBER);
                        if (debug) {
                            Logger.d(TAG, "解密前serialNumber:" + serialNumber);
                        }
                        serialNumber = MyEncryptorHelper.decryptKey(serialNumber);
                        if (debug) {
                            Logger.d(TAG, "解密后serialNumber:" + serialNumber);
                        }
                        IEncryptor aesHelper = MyEncryptorHelper.createAESHelper(serialNumber);
                        String decrypt = aesHelper.decryptToString(MyEncryptorHelper.getBase64Utils().decode(bytes));
                        if (debug) {
//                            Logger.d(TAG, "解密前:" + BaseUtils.getBase64Utils().getString(bytes));
                            Logger.d(TAG, "解密后:" + decrypt);
                        }
                        return response.newBuilder()
                                .body(ResponseBody.create(contentType, decrypt))
                                .build();
                    }

                }

            }
        }
        return response;
    }

    /**
     * 更具服务器返回的contentType判断是否需要解密
     *
     * @param contentType
     * @return
     */
    private boolean shouldDecrypt(String contentType) {
        if (contentType == null) {
            return false;
        }
        return contentType.contains(ContentType.JSON)
                || contentType.contains(ContentType.TEXT_PLAIN);
    }

}
